package pl.smath.renderer.model;

import com.google.gwt.user.client.ui.RootPanel;

import gwt.g2d.client.graphics.Surface;
import pl.smath.renderer.renderer.TermRendererException;
import pl.smath.renderer.utils.Cursor;
import pl.smath.renderer.utils.InteractionSocket;
import pl.smath.renderer.utils.Rectangle;

public class AtomView extends View {

	private View superscript;
	private View subscript;
	private View base;
	private Double subOffset;
	private Double supOffset;
	
	public AtomView( View base, View subscript, View superscript) {
		super("_^");
		this.setSubscript(subscript);
		this.setSuperscript(superscript);
		this.setBase(base);
	}

	/**
	 * render text at the current position
	 * @param canvas
	 */
	@Override
	public void render(Surface canvas, InteractionSocket socket) throws TermRendererException {
		if ((this.getFont() == null)||(this.getFontHeight() == null)) {
			throw new TermRendererException();
		}
		canvas.setFont(this.getFont());
		
		Cursor cursor = new Cursor(this.getCursor().getX(), this.getCursor().getY() - this.getBaselineOffset());
		
		Double minusWidth = this.minusSign.getWidth();
		
		if (this.isNegative()) this.minusSign.render(canvas, cursor);
		
		this.getBase().render(canvas, socket);
		this.getSubscript().render(canvas, socket);
		this.getSuperscript().render(canvas, socket);
		
		Double scriptsWidth;
		if (this.getSubscript().getWidth() > this.getSuperscript().getWidth())
			scriptsWidth = this.getSubscript().getWidth();
		else
			scriptsWidth = this.getSuperscript().getWidth();
		
		if (this.isNegative()) 
			cursor.setX(cursor.getX() + minusWidth + scriptsWidth);
		else
			cursor.setX(cursor.getX() + scriptsWidth);

	}
	
	/**
	 * set the position on canvas to render
	 * @param Cursor
	 */
	@Override
	public void setCursor(Cursor cursor) {
		super.setCursor(new Cursor(cursor.getX(), cursor.getY()));
					
		Double minusWidth = this.minusSign.getWidth();
			
		Cursor toSet = new Cursor(cursor.getX(), cursor.getY() - this.getBaselineOffset());
		if (this.isNegative()) toSet.setX(toSet.getX() + minusWidth);
		
		this.getBase().setCursor(new Cursor(toSet.getX(), toSet.getY()));
		toSet.setX(toSet.getX() + this.getBase().getWidth());
		this.getSubscript().setCursor(new Cursor(toSet.getX(), toSet.getY() + getSubOffset()));
		this.getSuperscript().setCursor(new Cursor(toSet.getX(), toSet.getY() - getSupOffset()));
	}
	
	/**
	 * @param font the font to set
	 */
	@Override
	public void setFont(String font) {
		if (font.indexOf("px")!=-1) {
			this.setFontHeight(new Double(font.substring(0, font.indexOf("px"))));
			this.font = font.substring(font.indexOf("px ")+3);
			this.minusSign.setFont(this.font, this.getFontHeight());

			this.setSubOffset(this.getFontHeight() * 0.3d);
			this.setSupOffset(this.getFontHeight() * 0.5d);
			
			this.getBase().setFont(font);
			
			if (this.getFontHeight() > 8) {
				this.getSubscript().setFont((this.getFontHeight() - 4) + "px " + this.font);
				this.getSuperscript().setFont((this.getFontHeight() - 4) + "px " + this.font);
			} else {
				this.getSubscript().setFont(font);
				this.getSuperscript().setFont(font);
			}
			
			update();
		} else {
			this.setFontHeight(null);
			this.font = null;
		}
	}
	
	/**
	 * updates the view after changes
	 */
	@Override
	public void update() {
		Surface surface = new Surface();
		surface.setFont(this.getFont());
		
		Double minusWidth = this.minusSign.getWidth();
		
		this.setRectangle(new Rectangle());
		this.setBaselineOffset(0d);

		Double scriptsWidth;
		if (this.getSubscript().getWidth() > this.getSuperscript().getWidth())
			scriptsWidth = this.getSubscript().getWidth();
		else
			scriptsWidth = this.getSuperscript().getWidth();
		
		this.setWidth(this.getBase().getWidth() + scriptsWidth);
		
		if(this.isNegative())
			this.setWidth(this.getWidth() + minusWidth);
		
		this.setHeight(Math.max(this.getBase().getHeight(), this.getSubscript().getHeight() + subOffset + supOffset));
	}
	
	/**
	 * @return the superscript
	 */
	public View getSuperscript() {
		return superscript;
	}

	/**
	 * @param superscript the superscript to set
	 */
	public void setSuperscript(View superscript) {
		this.superscript = superscript;
	}

	/**
	 * @return the subscript
	 */
	public View getSubscript() {
		return subscript;
	}

	/**
	 * @param subscript the subscript to set
	 */
	public void setSubscript(View subscript) {
		this.subscript = subscript;
	}

	/**
	 * @return the base
	 */
	public View getBase() {
		return base;
	}

	/**
	 * @param base the base to set
	 */
	public void setBase(View base) {
		this.base = base;
	}

	/**
	 * @return the subOffset
	 */
	public Double getSubOffset() {
		return subOffset;
	}

	/**
	 * @param subOffset the subOffset to set
	 */
	public void setSubOffset(Double subOffset) {
		this.subOffset = subOffset;
	}

	/**
	 * @return the supOffset
	 */
	public Double getSupOffset() {
		return supOffset;
	}

	/**
	 * @param supOffset the supOffset to set
	 */
	public void setSupOffset(Double supOffset) {
		this.supOffset = supOffset;
	}

}
